﻿// ===================================
// The use and distribution terms for this software are covered by the Microsoft public license, 
// visit for more info : http://testcommander.codeplex.com 
// 
// You must not remove this copyright notice, or any other, from this software
// 
// Senthil Maruthaiappan  senips@gmail.com
// ===================================

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using QAPro.Test.FitServices.Interfaces;
using QAPro.Test.Interfaces;
using QAPro.Test.Library;
using WiseLight.Framework.Lite.Container;
using fit;

namespace QAPro.Test.Addin.Fitnesse
{
    [InstanceBehaviour(typeof (IFitTestEngine), InstanceBehaviourType.AlwaysCreate)]
    public class FitTestEngine : IFitTestEngine
    {
        private IFitUtilService _fitUtilService;

        public IServices Services { get; set; }

        private IFitUtilService FitUtilityService
        {
            get
            {
                if (_fitUtilService == null)
                    _fitUtilService = Services.Get<IFitUtilService>();
                return _fitUtilService;
            }
        }

        #region IFitTestEngine Members

        public NotifyErrors OnNotifyTestRunErrors { get; set; }

        public NotifyEventDelegate OnTestComplete { get; set; }

        public void Run(ITestNode node)
        {
            RunTest(node);
        }

        #endregion

        private void RunTest(ITestNode node)
        {
            if ((!node.IsRunnable) || ((node as IFitRunnableDoc) == null))
                return;
            node.TestResult.StartTime = DateTime.Now;
            IList<string> vars = new List<string>();
            FitUtilityService.GetVariables(node, ref vars);
            foreach (string asm in FitUtilityService.GetAsmPaths(vars))
                Configuration.Instance.Assemblies.Add(asm);
            try
            {
                Parse parse = HtmlParser.Instance.Parse((node as IFitRunnableDoc).GetTestDocument());
                var storyTest = new StoryTest(parse, new TestEngineFixtureListener(node));
                storyTest.Execute();
            }
            catch (Exception e)
            {
                string parentPath = string.Empty;
                TreeChildEnumerator.FindParentPath(node, ref parentPath);
                OnNotifyTestRunErrors(node.Name + " ( " + parentPath + " )\n\r" + e.Message + "\n\r" + e.StackTrace);
            }

            if (OnTestComplete != null)
                OnTestComplete(node);
        }

        #region Nested type: TestEngineFixtureListener

        private class TestEngineFixtureListener : FixtureListener
        {
            private readonly ITestNode _testNode;

            private readonly StringBuilder sb = new StringBuilder();
            private bool _firstTable = true;

            public TestEngineFixtureListener(ITestNode node)
            {
                _testNode = node;
                _testNode.TestResult.Exceptions = 0;
                _testNode.TestResult.Right = 0;
                _testNode.TestResult.Wrong = 0;
            }

            #region FixtureListener Members

            public void TableFinished(Parse finishedTable)
            {
                string testResultDocument = TableToString(finishedTable);
                int startIdx = testResultDocument.IndexOf("{");
                int endIdx = testResultDocument.IndexOf("}");
                if ((startIdx == -1) || (endIdx == -1))
                    return;
                string testId = testResultDocument.Substring(startIdx + 1, endIdx - startIdx - 1);
                foreach (ITestNode node in _testNode.GetTreeChildEnumerator())
                {
                    if (node.ID.ToString().Equals(testId))
                    {
                        var fitResult = (node.TestResult as IFitResult);
                        fitResult.ResultText = testResultDocument.Replace("ID={" + testId + "}", "");
                        fitResult.EndTime = DateTime.Now;

                        fitResult.StartTime = _firstTable ? _testNode.TestResult.StartTime : DateTime.Now;
                    }
                }
                _firstTable = false;
            }

            public void TablesFinished(Parse theTables, Counts counts)
            {
                _testNode.TestResult.Exceptions += counts.Exceptions;
                _testNode.TestResult.Right += counts.Right;
                _testNode.TestResult.Wrong += counts.Wrong;
                _testNode.TestResult.EndTime = DateTime.Now;
            }

            #endregion

            private static string TableToString(Parse tables)
            {
                Parse more = tables.More;
                tables.More = null;
                var writer = new StringWriter();
                tables.Print(writer);
                string firstTable = writer.ToString();
                tables.More = more;
                return firstTable;
            }
        }

        #endregion
    }
}